package com.googlecode.kipler.container.dl;

import java.util.HashSet;
import java.util.Iterator;

import com.googlecode.kipler.common.Copyable;
import com.googlecode.kipler.container.generic.MultivalueHashMap;
import com.googlecode.kipler.syntax.concept.BooleanConcept;
import com.googlecode.kipler.syntax.concept.Concept;
import com.googlecode.kipler.syntax.concept.ConceptName;
import com.googlecode.kipler.syntax.concept.InequalityConstructor;
import com.googlecode.kipler.syntax.concept.LTLBinaryConcept;
import com.googlecode.kipler.syntax.concept.LTLUnaryConcept;
import com.googlecode.kipler.syntax.concept.Nominal;
import com.googlecode.kipler.syntax.concept.QualifiedNoRestriction;
import com.googlecode.kipler.syntax.concept.RoleQuantification;


/**
 * 
 * @author İnanç Seylan
 * 
 */
public class ConceptCategorizer implements Copyable<ConceptCategorizer> {
	private MultivalueHashMap<ConceptCategory, Concept> library = new MultivalueHashMap<ConceptCategory, Concept>();

	private ConceptCategory findCategory(Concept desc) {
		ConceptCategory result = null;
		if (desc instanceof ConceptName) {
			result = ConceptCategory.ATOMIC;
		} else if (desc instanceof BooleanConcept) {
			BooleanConcept bd = (BooleanConcept) desc;
			result = (bd.getConstructor() == BooleanConcept.Constructor.INTERSECTION) ? ConceptCategory.INTERSECTION
					: ConceptCategory.UNION;
		} else if (desc instanceof RoleQuantification) {
			RoleQuantification rq = (RoleQuantification) desc;
			result = (rq.getConstructor() == RoleQuantification.Constructor.ALL) ? ConceptCategory.ALL
					: ConceptCategory.SOME;
		} else if (desc instanceof QualifiedNoRestriction) {
			QualifiedNoRestriction qr = (QualifiedNoRestriction) desc;
			result = (qr.getConstructor() == InequalityConstructor.AT_MOST) ? ConceptCategory.AT_MOST
					: ConceptCategory.AT_LEAST;
		} else if (desc instanceof Nominal) {
			result = ConceptCategory.NOMINAL;
		} else if (desc instanceof LTLUnaryConcept) {
			LTLUnaryConcept unCon = (LTLUnaryConcept) desc;
			switch (unCon.getConstructor()) {
			case ALWAYS:
				result = ConceptCategory.ALWAYS;
				break;
			case SOMETIME:
				result = ConceptCategory.SOMETIME;
				break;
			case NEXT:
				result = ConceptCategory.NEXT;
				break;
			}
		} else if (desc instanceof LTLBinaryConcept) {
			LTLBinaryConcept unCon = (LTLBinaryConcept) desc;
			switch (unCon.getConstructor()) {
			case BEFORE:
				result = ConceptCategory.BEFORE;
				break;
			case UNTIL:
				result = ConceptCategory.UNTIL;
				break;
			}
		}
		return result;
	}

	public void add(Concept desc) {
		ConceptCategory cat = findCategory(desc);
		library.put(cat, desc);
	}

	public boolean contains(Concept desc) {
		ConceptCategory cat = findCategory(desc);
		return library.containsKeyValue(cat, desc);
	}

	public Iterator<Concept> conceptIterator() {
		return library.values().iterator();
	}

	public Iterator<Concept> categoryIterator(ConceptCategory category) {
		// return a copy of the set because while iterating in the ABox rules,
		// we might also add concepts to the same node. This prevents concurrent
		// modification exception.
		return new HashSet<Concept>(library.getValuesForKey(category))
				.iterator();
	}

	@SuppressWarnings("unchecked")
	public ConceptCategorizer copy() {
		ConceptCategorizer categorizer = new ConceptCategorizer();
		categorizer.library = (MultivalueHashMap<ConceptCategory, Concept>) this.library
				.copy();
		return categorizer;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj != null && (obj.getClass().equals(this.getClass()))) {
			ConceptCategorizer other = (ConceptCategorizer) obj;
			return library.equals(other.library);
		}
		return false;
	}

	@Override
	public int hashCode() {
		return library.hashCode();
	}

	protected boolean containsAllConceptsOf(ConceptCategorizer other) {
		boolean result = library.keySet().containsAll(other.library.keySet());
		Iterator<ConceptCategory> i = other.library.keySet().iterator();
		while (result && i.hasNext()) {
			ConceptCategory category = i.next();
			result = result
					&& library.getValuesForKey(category).containsAll(
							other.library.getValuesForKey(category));
		}
		return result;
	}

	protected boolean hasSameConceptsAs(ConceptCategorizer other) {
		boolean result = library.keySet().equals(other.library.keySet());
		Iterator<ConceptCategory> i = other.library.keySet().iterator();
		while (result && i.hasNext()) {
			ConceptCategory category = i.next();
			result = result
					&& library.getValuesForKey(category).equals(
							other.library.getValuesForKey(category));
		}
		return result;
	}

}
